package main

import "fmt"

// 泛型的写法如下
func Sum[T int | float64](a, b T) T {
	return a + b
}

func main() {
	fmt.Println(Sum(3, 4))
	fmt.Println(Sum(1.2, 2.7))

	// 第一种用法，显式的指明使用哪种类型，如下
	display := Sum[int](2012, 2022)
	fmt.Println(display)

	// 第二种用法，不指定类型，让编译器自行推断，如下
	extrapolateForYourself := Sum(3.1415926, 1.114514)
	fmt.Println(extrapolateForYourself)

	// 1.1 这是一个泛型切片，类型约束为 int | int32 | int64
	type GenericSlice[T int | int32 | int64] []T
	// 1.2 这里使用时就不能省略掉类型实参
	g := GenericSlice[int]{1, 2, 3}
	fmt.Println(g)

	// 2.1 这是一个泛型哈希表，键的类型必须是可比较的，所以使用 comparable 接口，
	// 值的类型约束为 V int | string | byte
	type GenericMap[K comparable, V int | string | byte] map[K]V
	gmap1 := GenericMap[int, string]{1: "hello world"}
	fmt.Println(gmap1)
	gmap2 := make(GenericMap[string, byte], 0)
	gmap2["迪迦"] = 1
	fmt.Println(gmap2)

	// 3.1 这是一个泛型结构体，类型约束为 T int | string
	type GenericStruct[T int | string] struct {
		Name string
		Id   T
	}
	g1 := GenericStruct[int]{
		Name: "jack",
		Id:   1024,
	}
	fmt.Println(g1)
	g2 := GenericStruct[string]{
		Name: "Mike",
		Id:   "1024",
	}
	fmt.Println(g2)

	// 4.1 这是一个泛型切片形参的例子
	// T的数据类型：int或string
	// S的数据类型：int类型的切片或string
	type Company[T int | string, S []int | string] struct {
		Name  string
		Id    T
		Stuff S
	}
	c1 := Company[int, []int]{
		Name:  "lili",
		Id:    1,
		Stuff: []int{1},
	}
	var c2 = Company[string, string]{
		Name:  "lili",
		Id:    "2205151117",
		Stuff: "world",
	}
	fmt.Println(c1)
	fmt.Println(c2)
}
